package com.beta.auth.filter;

import com.alibaba.fastjson.JSON;
import com.beta.auth.constants.BusinessConstants;
import com.beta.auth.utils.ResponseUtils;
import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zdwang
 * @Description 重限流过滤器
 **/
@Slf4j
@RefreshScope
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 1) //这个不能排在corsFilter前面，否则前端会出现跨域访问
public class RateLimiterFilter implements Filter, InitializingBean {

    private static final long DEFAULT_RATE_LIMITER = 100L;

    /**
     * 限流路径配置
     */
    @Value("${rateLimiter.uris:}")
    private List<String> rateLimiterUris;


    private Map<String, RateLimiter> rateLimiterMap = new HashMap<>();

    @Override
    public void init(FilterConfig filterConfig) {
    }

    private void parseToMap() {
        if (CollectionUtils.isEmpty(rateLimiterUris)) {
            log.error("init rateLimiter is null!");
            return;
        }

        log.info("rateLimiter config uris :{}", rateLimiterUris);

        //加载流量限流配置到Map
        loadRateLimiterUri(rateLimiterMap, rateLimiterUris);

        log.info("rateLimiter config uris map :{}", JSON.toJSONString(rateLimiterMap));
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        //获取请求 URI
        String requestURI = request.getRequestURI();
        // 防止出现 a/b/c/、a/b/c//、a/b/c///
        while (requestURI.endsWith("/")) {
            requestURI = requestURI.substring(0, requestURI.length() - 1).trim();
        }

        // 1、接口限流处理
        boolean isFilterPass = isFilterPass(rateLimiterMap, requestURI);
        if (!isFilterPass) {
            log.warn("do RateLimiterFilter, requestURI:{}", requestURI);
            // 接口限流
            ResponseUtils.toErrPage(BusinessConstants.SYSTEM_ERROR_MSG, BusinessConstants.LIMIT_CODE, response);
            return;
        }
        filterChain.doFilter(request, servletResponse);
    }

    private void loadRateLimiterUri(Map<String, RateLimiter> rateLimiterMap, List<String> rateLimiterUris) {
        Map<String, RateLimiter> tmp = new HashMap<>();
        for (String rateLimiterUri : rateLimiterUris) {
            if (StringUtils.isBlank(rateLimiterUri)) {
                continue;
            }
            String uri;
            long limit = DEFAULT_RATE_LIMITER;

            if (rateLimiterUri.contains("-")) {
                uri = rateLimiterUri.substring(0, rateLimiterUri.lastIndexOf("-")).trim();
                String permitsPerSecondStr = rateLimiterUri.substring(rateLimiterUri.lastIndexOf("-") + 1).trim();
                limit = NumberUtils.isDigits(permitsPerSecondStr) ? Long.parseLong(permitsPerSecondStr) : DEFAULT_RATE_LIMITER;
            } else {
                uri = rateLimiterUri;
            }
            while (uri.endsWith("/")) {
                uri = uri.substring(0, uri.length() - 1).trim();
            }

            if (limit == 0) {
                limit = Long.MAX_VALUE;
            }

            RateLimiter rateLimiter = RateLimiter.create(limit);
            tmp.put(uri, rateLimiter);
        }
        rateLimiterMap.clear();
        rateLimiterMap.putAll(tmp);
    }

    /**
     * 是否没有达到限制，可以通行
     *
     * @param rateLimiterMap
     * @param requestURI
     * @return
     */
    private boolean isFilterPass(Map<String, RateLimiter> rateLimiterMap, String requestURI) {
        if (rateLimiterMap == null || rateLimiterMap.isEmpty()) {
            return true;
        }
        RateLimiter rateLimiter = rateLimiterMap.get(requestURI);
        if (rateLimiter != null) {
            if(rateLimiter.getRate() == Long.MAX_VALUE) {
                return false;
            }

            if (rateLimiter.tryAcquire()) {
                return true;
            } else {
                return false;
            }
        } else {//没有限制，则直接返回true
            return true;
        }
    }

    @Override
    public void destroy() {
    }

    @Override
    public void afterPropertiesSet() {
        parseToMap();
    }
}
